package com.polaris.live.widget.task

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewTreeObserver
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.RelativeLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.doOnLayout
import com.blankj.utilcode.util.StringUtils
import com.bumptech.glide.Glide
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.constant.PagConst
import com.polaris.live.common.ext.autoDp
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.databinding.WidgetActiveTodayBinding
import com.polaris.live.databinding.WidgetTaskActiveNodeBinding
import com.polaris.live.dialog.ActiveRewardDialog
import com.polaris.live.resp.back_resp.ActiveTask
import com.polaris.live.resp.back_resp.ActiveTaskVo
import com.polaris.live.utils.file.FileUtils
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.utils.viewscope.autoDisposeScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.libpag.PAGFile
import org.libpag.PAGImage
import org.libpag.PAGView
import java.util.concurrent.TimeUnit

/**
 * ActiveTodayView 今日活跃
 *
 * @author Created by 天晴 on 2024/1/24 19:17
 * @since 1.0.0
 **/
class ActiveTodayView(context: Context, attributeSet: AttributeSet) :
    RelativeLayout(context, attributeSet) {

    private val mBinding = WidgetActiveTodayBinding.inflate(LayoutInflater.from(context), this)

    private var mWidth = 0

    private val maxWidth = 75.autoDp

    private var oneDayProgressWidth = maxWidth //一個進度的寬度
    private var oneWeekProgressWidth = maxWidth //一個進度的寬度
    private var activeTask: ActiveTaskVo? = null
    private var remainingTime: Long = -1

    private var click: ((dailyTask: Boolean, activeValue: Long) -> Unit)? = null
    private var clickBack: ((explainType: Long) -> Unit)? = null

    init {
        getMyWidth()
        startTime()
    }

    private fun getMyWidth() {
        if (mWidth != 0) return
        mBinding.root.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                if (ViewUtils.isContextValid(context)) {
                    mWidth = mBinding.root.width
                    activeTask?.let {
                        setData(it)
                    }
                }

                mBinding.root.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })

    }

    private var timeJob: Job? = null
    private fun startTime() {
        cancelTime()
        timeJob = CoroutineScopeManager.ioScope.launch {
            while (isActive) {
                delay(1000)
                remainingTime -= 1000
                withContext(CoroutineScopeManager.mainDispatcher) {
                    setTime()
                }

            }
        }
    }

    private fun cancelTime() {
        timeJob?.cancel()
        timeJob = null
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        cancelTime()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        startTime()
    }

    private fun setTime() {
        mBinding.countdownTv.text = if (remainingTime > 0) {
            formatMillisecondsToTime(remainingTime)
        } else {
            "00:00:00"
        }
    }

    private fun formatMillisecondsToTime(millis: Long): String {
        val hours = TimeUnit.MILLISECONDS.toHours(millis)
        val minutes = TimeUnit.MILLISECONDS.toMinutes(millis) % 60
        val seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60
        return String.format("%02d:%02d:%02d", hours, minutes, seconds)
    }

    fun setPathType(pagView: PAGView, path: String) {
        autoDisposeScope.launch {
            try {
                val filePath = FileUtils.getAssetsToFilePag(PagConst.TASK_CENTER_ACTIVITY_SHAKE)
                val pagFile = PAGFile.Load(filePath)
                val bitmapBack = ImageUtils.loadNetImageBitmap(context, path, 40.autoDp, 40.autoDp)
                val pagImageBack = PAGImage.FromBitmap(bitmapBack)
                pagFile?.replaceImage(0, pagImageBack)
                withContext(CoroutineScopeManager.mainDispatcher) {
                    if (isActive) {
                        pagView.composition = pagFile
                        pagView.flush()
                        pagView.setRepeatCount(-1)
                        pagView.play()
                    }
                }
            } catch (_: Exception) {
            }
        }
    }

    fun setData(activeTask: ActiveTaskVo) {
        this.activeTask = activeTask
        val show = activeTask.tasks.isNotEmpty() || activeTask.weekTasks.isNotEmpty()
        visibility = if (show) View.VISIBLE else View.GONE

        if (show) {
            getMyWidth()
        }
        if (remainingTime == -1L) {
            remainingTime = (activeTask.expiredTime?.toLongOrNull() ?: 0) - CacheUtil.getServerTime()
        }
        mBinding.apply {
            activeTv.text =
                StringUtils.getString(com.polaris.live.translation.R.string.today_active_value, activeTask.value)
            activeWeekTv.text =
                StringUtils.getString(com.polaris.live.translation.R.string.week_active_value, activeTask.weekValue)
            setTime()
        }
        if (mWidth != 0) {
            if (activeTask.tasks.isNotEmpty()) {
                setTodayView(activeTask.tasks, activeTask.total, activeTask.value)
            }
            if (activeTask.weekTasks.isNotEmpty()) {
                setWeekView(activeTask.weekTasks, activeTask.weekTotal, activeTask.weekValue)
            }
        }
    }

    private fun setTodayView(tasks: List<ActiveTask>, total: Long, value: Long) {
        mBinding.progressCl.removeAllViews()
        oneDayProgressWidth = if (tasks.size <= 5) {
            (mWidth - 25.autoDp) / tasks.size
        } else {
            maxWidth
        }
        var pId = ConstraintLayout.LayoutParams.PARENT_ID
        var upIndex = 0L
        tasks.forEachIndexed { index, da ->
            val v = da.value - upIndex
            val v2 = value - upIndex
            val nValue = if (v2 < 0) {
                0
            } else if (v2 in 0..v) {
                v2
            } else {
                v
            }
            val progressWidth = if (index == 0) {
                oneDayProgressWidth - 15.autoDp
            } else {
                oneDayProgressWidth
            }

            val progress = newProgressBar(progressWidth, pId)
            mBinding.progressCl.addView(progress)
            progress.doOnLayout {
                progress.max = v.toInt()
                progress.progress = nValue.toInt()
            }
            pId = progress.id
            addDayNodeView(progress, da)
            upIndex = da.value
        }
    }

    private fun setWeekView(tasks: List<ActiveTask>, total: Long, value: Long) {
        mBinding.weekProgressCl.removeAllViews()
        oneWeekProgressWidth = if (tasks.size <= 5) {
            (mWidth - 25.autoDp) / tasks.size
        } else {
            maxWidth
        }
        var pId = ConstraintLayout.LayoutParams.PARENT_ID
        var upIndex = 0L
        tasks.forEachIndexed { index, da ->
            val v = da.value - upIndex
            val v2 = value - upIndex
            val nValue = if (v2 < 0) {
                0
            } else if (v2 in 0..v) {
                v2
            } else {
                v
            }
            val progressWidth = if (index == 0) {
                oneWeekProgressWidth - 15.autoDp
            } else {
                oneWeekProgressWidth
            }

            val progress = newProgressBar(progressWidth, pId)
            mBinding.weekProgressCl.addView(progress)
            progress.doOnLayout {
                progress.max = v.toInt()
                progress.progress = nValue.toInt()
            }
            pId = progress.id
            addWeekNodeView(progress, da)
            upIndex = da.value
        }
    }

    private fun addDayNodeView(
        view: View,
        item: ActiveTask,
    ) {
        mBinding.todayScrollView.post {
            if (!this.isAttachedToWindow) return@post
            val viewId = View.generateViewId()
            if (item.status == 1L) {
                val pagView = PAGView(context)
                pagView.id = viewId
                val lp = ConstraintLayout.LayoutParams(50.autoDp, 50.autoDp)
                lp.topToTop = view.id
                lp.bottomToBottom = view.id
                lp.endToEnd = view.id
                lp.marginEnd = (-20).autoDp
                pagView.layoutParams = lp
                mBinding.progressCl.addView(pagView)
                setPathType(pagView, item.processingIcon)
                pagView.setOnSingleClickListener {
                    click?.invoke(true, item.value)
                }
            } else {
                val imageView = ImageView(context)
                imageView.id = viewId
                val lp = ConstraintLayout.LayoutParams(40.autoDp, 40.autoDp)
                lp.topToTop = view.id
                lp.bottomToBottom = view.id
                lp.endToEnd = view.id
                lp.marginEnd = (-20).autoDp
                imageView.layoutParams = lp
                when (item.status) {
                    0L -> { //进行中
                        Glide.with(imageView)
                            .load(ImageUtils.imgPath(item.processingIcon))
                            .into(imageView)
                    }

                    1L -> { //可领取

                    }

                    2L -> { //已完成
                        Glide.with(imageView)
                            .load(ImageUtils.imgPath(item.receivedIcon))
                            .into(imageView)
                    }
                }
                mBinding.progressCl.addView(imageView)
                imageView.setOnSingleClickListener {
                    ActiveRewardDialog.show(context, false, item)
                }
            }
            val mNodeBinding = WidgetTaskActiveNodeBinding.inflate(LayoutInflater.from(context), null, false)
            mNodeBinding.apply {
                tvCount.text = "${item.value}"
            }
            val node = mNodeBinding.root
            val nodeLp = ConstraintLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
            nodeLp.topMargin = 10.autoDp
            nodeLp.topToBottom = view.id
            nodeLp.startToStart = viewId
            nodeLp.endToEnd = viewId
            node.layoutParams = nodeLp
            mBinding.progressCl.addView(node)
            node.setOnSingleClickListener {
                clickBack?.invoke(4)
            }
        }

    }

    private fun addWeekNodeView(
        view: View,
        item: ActiveTask,
    ) {
        mBinding.weekScrollView.post {
            val viewId = View.generateViewId()
            if (item.status == 1L) {
                val pagView = PAGView(context)
                pagView.id = viewId
                val lp = ConstraintLayout.LayoutParams(50.autoDp, 50.autoDp)
                lp.topToTop = view.id
                lp.bottomToBottom = view.id
                lp.endToEnd = view.id
                lp.marginEnd = (-20).autoDp
                pagView.layoutParams = lp
                mBinding.weekProgressCl.addView(pagView)
                setPathType(pagView, item.processingIcon)
                pagView.setOnSingleClickListener {
                    click?.invoke(false, item.value)
                }
            } else {
                val imageView = ImageView(context)
                imageView.id = viewId
                val lp = ConstraintLayout.LayoutParams(40.autoDp, 40.autoDp)
                lp.topToTop = view.id
                lp.bottomToBottom = view.id
                lp.endToEnd = view.id
                lp.marginEnd = (-20).autoDp
                imageView.layoutParams = lp
                when (item.status) {
                    0L -> { //进行中
                        Glide.with(imageView)
                            .load(ImageUtils.imgPath(item.processingIcon))
                            .into(imageView)
                    }

                    1L -> { //可领取

                    }

                    2L -> { //已完成
                        Glide.with(imageView)
                            .load(ImageUtils.imgPath(item.receivedIcon))
                            .into(imageView)
                    }
                }
                mBinding.weekProgressCl.addView(imageView)
                imageView.setOnSingleClickListener {
                    ActiveRewardDialog.show(context, true, item)
                }
            }

            val mNodeBinding = WidgetTaskActiveNodeBinding.inflate(LayoutInflater.from(context), null, false)
            mNodeBinding.apply {
                tvCount.text = "${item.value}"
            }
            val node = mNodeBinding.root
            val nodeLp = ConstraintLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
            nodeLp.topMargin = 10.autoDp
            nodeLp.topToBottom = view.id
            nodeLp.startToStart = viewId
            nodeLp.endToEnd = viewId
            node.layoutParams = nodeLp
            mBinding.weekProgressCl.addView(node)
            node.setOnSingleClickListener {
                clickBack?.invoke(4)
            }
        }

    }

    private fun newProgressBar(
        mWidth: Int,
        start: Int = ConstraintLayout.LayoutParams.PARENT_ID,
    ): ProgressBar {
        val progressBar = ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal).apply {
            id = View.generateViewId()
            layoutParams = ConstraintLayout.LayoutParams(
                mWidth,
                3.autoDp
            ).apply {
                topToTop = ConstraintLayout.LayoutParams.PARENT_ID
                if (start == ConstraintLayout.LayoutParams.PARENT_ID) {
                    startToStart = ConstraintLayout.LayoutParams.PARENT_ID
                } else {
                    startToEnd = start
                }
                topMargin = 30.autoDp
            }
            progressDrawable =
                ContextCompat.getDrawable(context, com.polaris.live.R.drawable.task_progress_bar)?.mutate()
        }
        return progressBar
    }

    fun setOnClickListener(
        click: (dailyTask: Boolean, activeValue: Long) -> Unit,
        clickBack: ((explainType: Long) -> Unit)? = null,
    ) {
        this.click = click
        this.clickBack = clickBack
    }

}